package com.suray.wcs.service.pojo.rgv.extract.log.process;

import com.mysql.cj.util.StringUtils;
import com.suray.basic.wcs.utils.Crc16;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.basic.wcs.utils.WcsFuncUtil;
import com.suray.wcs.service.core.util.LongConnSendUtilLora;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.util.WcsUtil;

import java.io.*;
import java.util.Arrays;

public class RgvExtractLogProcess {

    private Rgv rgv;
    private String logName;

    private final byte ACK = 6;
    private final byte EOT = 4;

    private volatile byte[] receiveData;
    private volatile boolean endHandle;

    public RgvExtractLogProcess(Rgv rgv, String logName) {
        this.rgv = rgv;
        this.logName = logName;

        endHandle = false;
    }

    public void start() throws IOException {
        String logFile = System.getProperty("user.dir") + File.separator + "rgv_log" + File.separator +
                rgv.getRgvName() + File.separator + logName + ".log";

        WcsUtil.createPaper(logFile);
        File file = new File(logFile);
        FileOutputStream fileOutputStream = new FileOutputStream(file);

        try {
            extractLogToFile(fileOutputStream);
        } finally {
            fileOutputStream.close();
        }
    }

    public void extractLogToFile(FileOutputStream fileOutputStream) throws IOException {
        int index = 0;
        byte[] data = handle();
        analyzeMessage(data, index++, fileOutputStream);

        sendACK();
        WcsUtil.delay(10);
        send("C");
        data = receiveData(1000);

        while (analyzeMessage(data, index++, fileOutputStream)) {
            if (index > 0xFF) {
                index = 0;
            }
            data = extractLogData(0);
        }

        sendACK();
        send("C");
        try {
            receiveData(1000);
        } catch (IOException e) {
            //如果未收到该报文也不用做任何处理
            e.printStackTrace();
        }
    }

    private void sendACK() throws IOException {
        send(new byte[]{ACK});
    }

    private byte[] handle() throws IOException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    receiveData = receiveData(8000);
                } catch (IOException e) {
                    LoggerUtil.error(logName + "日志提取，握手失败", this.getClass());
                } finally {
                    endHandle = true;
                }
            }
        }).start();

        while (!endHandle) {
            send("C");
            WcsUtil.delay(1000);
        }

        if (receiveData == null) {
            throw new RuntimeException(logName + "日志提取，握手失败");
        }

        return receiveData;
    }

    private boolean analyzeMessage(byte[] data, int index, FileOutputStream fileOutputStream) throws IOException {
        if (data.length < 1024) {
            if (data[0] == EOT) {
                //结束
                return false;
            }
        }

        checkMessage(data, index);
        fileOutputStream.write(data, 3, 1024);
        return true;
    }

    private void checkMessage(byte[] data, int count) {
        if (data.length != (1024 + 3 + 2)) {
            throw new RuntimeException("报文长度错误");
        }

        int crc = WcsFuncUtil.combineToWord(data[data.length - 1], data[data.length - 2]);
        if (crc != Crc16.Cal_CRC16(Arrays.copyOfRange(data, 3, data.length - 2), data.length - 5)) {
            throw new RuntimeException("crc校验失败");
        }

        if (data[0] != 2) {
            throw new RuntimeException("报文头错误");
        }

        if (data[1] != (byte)count || (data[1] + data[2]) != (byte)0xFF) {
            throw new RuntimeException("包头校验数据错误");
        }
    }

    public static void main(String[] args) {
        byte[] data = {'S', 'T', 'X', 0, 0, -1};
        String.valueOf(data);
        StringUtils.toString(data);
    }

    private byte[] head(int count) throws IOException {
        try {
            send("C");
            return receiveData();
        } catch (IOException e) {
            if (count > 0) {
                WcsUtil.delay(1000);
                return head(--count);
            } else {
                throw e;
            }
        }
    }

    private byte[] extractLogData(int count) throws IOException {
        try {
            sendACK();
            return receiveData();
        } catch (IOException e) {
            if (count > 0) {
                return head(--count);
            } else {
                throw e;
            }
        }
    }

    private void send(byte[] data) throws IOException {
        LongConnSendUtilLora longConnSendUtilLora = LongConnSendUtilLora.getSocketSendUtil(rgv);
        longConnSendUtilLora.send(data, logName + "提取日志");
    }

    private void send(String str) throws IOException {
        LongConnSendUtilLora longConnSendUtilLora = LongConnSendUtilLora.getSocketSendUtil(rgv);
        longConnSendUtilLora.send(str.getBytes(), logName + "提取日志");
    }

    private byte[] receiveData() throws IOException {
        LongConnSendUtilLora longConnSendUtilLora = LongConnSendUtilLora.getSocketSendUtil(rgv);
        return longConnSendUtilLora.getReturnBytes(logName + "提取日志", 100);
    }

    private byte[] receiveData(Integer timeOut) throws IOException {
        LongConnSendUtilLora longConnSendUtilLora = LongConnSendUtilLora.getSocketSendUtil(rgv);
        return longConnSendUtilLora.getReturnBytes(logName + "提取日志", timeOut);
    }
}
